// streambuf standard header
#pragma once
#ifndef _STREAMBUF_
#define _STREAMBUF_
#ifndef RC_INVOKED
#include <xiosbase>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
// CLASS TEMPLATE basic_streambuf
template <class _Elem,
    class _Traits>
class basic_streambuf { // control read/write buffers
protected:
    __CLR_OR_THIS_CALL basic_streambuf() : _Plocale(new locale) { // construct with no buffers
        _Init();
    }

    __CLR_OR_THIS_CALL basic_streambuf(_Uninitialized) { // construct uninitialized
    }

    __CLR_OR_THIS_CALL basic_streambuf(const basic_streambuf& _Right)
        : _Plocale(new locale(_Right.getloc())) { // construct by copying _Right
        _Init();
        setp(_Right.pbase(), _Right.pptr(), _Right.epptr());
        setg(_Right.eback(), _Right.gptr(), _Right.egptr());
    }

    basic_streambuf& __CLR_OR_THIS_CALL operator=(const basic_streambuf& _Right) { // assign from _Right
        if (this != _STD addressof(_Right)) { // different, worth copying
            setp(_Right.pbase(), _Right.pptr(), _Right.epptr());
            setg(_Right.eback(), _Right.gptr(), _Right.egptr());
            pubimbue(_Right.getloc());
        }
        return *this;
    }

    void __CLR_OR_THIS_CALL swap(basic_streambuf& _Right) { // swap with _Right
        if (this != _STD addressof(_Right)) { // different, worth swapping
            _Elem* _Pfirst0 = pbase();
            _Elem* _Pnext0  = pptr();
            _Elem* _Pend    = epptr();
            _Elem* _Gfirst0 = eback();
            _Elem* _Gnext0  = gptr();
            _Elem* _Gend    = egptr();

            setp(_Right.pbase(), _Right.pptr(), _Right.epptr());
            _Right.setp(_Pfirst0, _Pnext0, _Pend);

            setg(_Right.eback(), _Right.gptr(), _Right.egptr());
            _Right.setg(_Gfirst0, _Gnext0, _Gend);

            _STD swap(_Plocale, _Right._Plocale);
        }
    }

public:
    using char_type   = _Elem;
    using traits_type = _Traits;

    virtual __CLR_OR_THIS_CALL ~basic_streambuf() noexcept { // destroy the object
        delete _Plocale;
    }

    using int_type = typename _Traits::int_type;
    using pos_type = typename _Traits::pos_type;
    using off_type = typename _Traits::off_type;

    pos_type __CLR_OR_THIS_CALL pubseekoff(off_type _Off, ios_base::seekdir _Way,
        ios_base::openmode _Mode = ios_base::in | ios_base::out) { // change position by _Off, according to _Way, _Mode
        return seekoff(_Off, _Way, _Mode);
    }

#if _HAS_OLD_IOSTREAMS_MEMBERS
    pos_type __CLR_OR_THIS_CALL pubseekoff(off_type _Off, ios_base::seek_dir _Way,
        ios_base::open_mode _Mode) { // change position by _Off, according to _Way, _Mode (old style)
        return pubseekoff(_Off, (ios_base::seekdir) _Way, (ios_base::openmode) _Mode);
    }
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    pos_type __CLR_OR_THIS_CALL pubseekpos(pos_type _Pos,
        ios_base::openmode _Mode = ios_base::in | ios_base::out) { // change position to _Pos, according to _Mode
        return seekpos(_Pos, _Mode);
    }

#if _HAS_OLD_IOSTREAMS_MEMBERS
    pos_type __CLR_OR_THIS_CALL pubseekpos(pos_type _Pos,
        ios_base::open_mode _Mode) { // change position to _Pos, according to _Mode (old style)
        return seekpos(_Pos, (ios_base::openmode) _Mode);
    }
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    basic_streambuf* __CLR_OR_THIS_CALL pubsetbuf(_Elem* _Buffer,
        streamsize _Count) { // offer _Buffer to external agent
        return setbuf(_Buffer, _Count);
    }

    locale __CLR_OR_THIS_CALL pubimbue(const locale& _Newlocale) { // set locale to argument
        locale _Oldlocale = *_Plocale;
        imbue(_Newlocale);
        *_Plocale = _Newlocale;
        return _Oldlocale;
    }

    locale __CLR_OR_THIS_CALL getloc() const { // get locale
        return *_Plocale;
    }

    streamsize __CLR_OR_THIS_CALL in_avail() { // return count of buffered input characters
        streamsize _Res = _Gnavail();
        return 0 < _Res ? _Res : showmanyc();
    }

    int __CLR_OR_THIS_CALL pubsync() { // synchronize with external agent
        return sync();
    }

    int_type __CLR_OR_THIS_CALL sbumpc() { // get a character and point past it
        return 0 < _Gnavail() ? _Traits::to_int_type(*_Gninc()) : uflow();
    }

    int_type __CLR_OR_THIS_CALL sgetc() { // get a character and don't point past it
        return 0 < _Gnavail() ? _Traits::to_int_type(*gptr()) : underflow();
    }

    streamsize __CLR_OR_THIS_CALL sgetn(_Elem* _Ptr,
        streamsize _Count) { // get up to _Count characters into array beginning at _Ptr
        return xsgetn(_Ptr, _Count);
    }

    int_type __CLR_OR_THIS_CALL snextc() { // point to next character and return it
        return 1 < _Gnavail() ? _Traits::to_int_type(*_Gnpreinc())
                              : _Traits::eq_int_type(_Traits::eof(), sbumpc()) ? _Traits::eof() : sgetc();
    }

    int_type __CLR_OR_THIS_CALL sputbackc(_Elem _Ch) { // put back _Ch
        return gptr() != nullptr && eback() < gptr() && _Traits::eq(_Ch, gptr()[-1])
                   ? _Traits::to_int_type(*_Gndec())
                   : pbackfail(_Traits::to_int_type(_Ch));
    }

#if _HAS_OLD_IOSTREAMS_MEMBERS
    void __CLR_OR_THIS_CALL stossc() { // point past a character
        if (0 < _Gnavail()) {
            _Gninc();
        } else {
            uflow();
        }
    }
#endif // _HAS_OLD_IOSTREAMS_MEMBERS

    int_type __CLR_OR_THIS_CALL sungetc() { // back up one position
        return gptr() != nullptr && eback() < gptr() ? _Traits::to_int_type(*_Gndec()) : pbackfail();
    }

    int_type __CLR_OR_THIS_CALL sputc(_Elem _Ch) { // put a character
        return 0 < _Pnavail() ? _Traits::to_int_type(*_Pninc() = _Ch) : overflow(_Traits::to_int_type(_Ch));
    }

    streamsize __CLR_OR_THIS_CALL sputn(const _Elem* _Ptr,
        streamsize _Count) { // put _Count characters from array beginning at _Ptr
        return xsputn(_Ptr, _Count);
    }

    virtual void __CLR_OR_THIS_CALL _Lock() { // set the thread lock (overridden by basic_filebuf)
    }

    virtual void __CLR_OR_THIS_CALL _Unlock() { // clear the thread lock (overridden by basic_filebuf)
    }

protected:
    _Elem* __CLR_OR_THIS_CALL eback() const { // return beginning of read buffer
        return *_IGfirst;
    }

    _Elem* __CLR_OR_THIS_CALL gptr() const { // return current position in read buffer
        return *_IGnext;
    }

    _Elem* __CLR_OR_THIS_CALL pbase() const { // return beginning of write buffer
        return *_IPfirst;
    }

    _Elem* __CLR_OR_THIS_CALL pptr() const { // return current position in write buffer
        return *_IPnext;
    }

    _Elem* __CLR_OR_THIS_CALL egptr() const { // return end of read buffer
        return *_IGnext + *_IGcount;
    }

    void __CLR_OR_THIS_CALL gbump(int _Off) { // alter current position in read buffer by _Off
        *_IGcount -= _Off;
        *_IGnext += _Off;
    }

    void __CLR_OR_THIS_CALL setg(_Elem* _First, _Elem* _Next, _Elem* _Last) { // set pointers for read buffer
        *_IGfirst = _First;
        *_IGnext  = _Next;
        *_IGcount = (int) (_Last - _Next);
    }

    _Elem* __CLR_OR_THIS_CALL epptr() const { // return end of write buffer
        return *_IPnext + *_IPcount;
    }

    _Elem* __CLR_OR_THIS_CALL _Gndec() { // decrement current position in read buffer
        ++*_IGcount;
        return --*_IGnext;
    }

    _Elem* __CLR_OR_THIS_CALL _Gninc() { // increment current position in read buffer
        --*_IGcount;
        return (*_IGnext)++;
    }

    _Elem* __CLR_OR_THIS_CALL _Gnpreinc() { // preincrement current position in read buffer
        --*_IGcount;
        return ++(*_IGnext);
    }

    streamsize __CLR_OR_THIS_CALL _Gnavail() const { // count number of available elements in read buffer
        return *_IGnext != nullptr ? *_IGcount : 0;
    }

    void __CLR_OR_THIS_CALL pbump(int _Off) { // alter current position in write buffer by _Off
        *_IPcount -= _Off;
        *_IPnext += _Off;
    }

    void __CLR_OR_THIS_CALL setp(_Elem* _First, _Elem* _Last) { // set pointers for write buffer
        *_IPfirst = _First;
        *_IPnext  = _First;
        *_IPcount = (int) (_Last - _First);
    }

    void __CLR_OR_THIS_CALL setp(
        _Elem* _First, _Elem* _Next, _Elem* _Last) { // set pointers for write buffer, extended version
        *_IPfirst = _First;
        *_IPnext  = _Next;
        *_IPcount = (int) (_Last - _Next);
    }

    _Elem* __CLR_OR_THIS_CALL _Pninc() { // increment current position in write buffer
        --*_IPcount;
        return (*_IPnext)++;
    }

    streamsize __CLR_OR_THIS_CALL _Pnavail() const { // count number of available positions in write buffer
        return *_IPnext != nullptr ? *_IPcount : 0;
    }

    void __CLR_OR_THIS_CALL _Init() { // initialize buffer parameters for no buffers
        _IGfirst = &_Gfirst;
        _IPfirst = &_Pfirst;
        _IGnext  = &_Gnext;
        _IPnext  = &_Pnext;
        _IGcount = &_Gcount;
        _IPcount = &_Pcount;
        setp(nullptr, nullptr);
        setg(nullptr, nullptr, nullptr);
    }

    void __CLR_OR_THIS_CALL _Init(_Elem** _Gf, _Elem** _Gn, int* _Gc, _Elem** _Pf, _Elem** _Pn,
        int* _Pc) { // initialize buffer parameters as specified
        _IGfirst = _Gf;
        _IPfirst = _Pf;
        _IGnext  = _Gn;
        _IPnext  = _Pn;
        _IGcount = _Gc;
        _IPcount = _Pc;
    }

    virtual int_type __CLR_OR_THIS_CALL overflow(int_type = _Traits::eof()) { // put a character to stream (always fail)
        return _Traits::eof();
    }

    virtual int_type __CLR_OR_THIS_CALL pbackfail(
        int_type = _Traits::eof()) { // put a character back to stream (always fail)
        return _Traits::eof();
    }

    virtual streamsize __CLR_OR_THIS_CALL showmanyc() { // return count of input characters
        return 0;
    }

    virtual int_type __CLR_OR_THIS_CALL underflow() { // get a character from stream, but don't point past it
        return _Traits::eof();
    }

    virtual int_type __CLR_OR_THIS_CALL uflow() { // get a character from stream, point past it
        return _Traits::eq_int_type(_Traits::eof(), underflow()) ? _Traits::eof() : _Traits::to_int_type(*_Gninc());
    }

    virtual streamsize __CLR_OR_THIS_CALL xsgetn(_Elem* _Ptr, streamsize _Count) { // get _Count characters from stream
        const streamsize _Start_count = _Count;

        while (0 < _Count) {
            streamsize _Size = _Gnavail();
            if (0 < _Size) { // copy from read buffer
                if (_Count < _Size) {
                    _Size = _Count;
                }

                _Traits::copy(_Ptr, gptr(), static_cast<size_t>(_Size));
                _Ptr += _Size;
                _Count -= _Size;
                gbump(static_cast<int>(_Size));
            } else {
                const int_type _Meta = uflow();
                if (_Traits::eq_int_type(_Traits::eof(), _Meta)) {
                    break; // end of file, quit
                }

                // get a single character
                *_Ptr++ = _Traits::to_char_type(_Meta);
                --_Count;
            }
        }

        return _Start_count - _Count;
    }

    virtual streamsize __CLR_OR_THIS_CALL xsputn(
        const _Elem* _Ptr, streamsize _Count) { // put _Count characters to stream
        const streamsize _Start_count = _Count;
        while (0 < _Count) {
            streamsize _Size = _Pnavail();
            if (0 < _Size) { // copy to write buffer
                if (_Count < _Size) {
                    _Size = _Count;
                }

                _Traits::copy(pptr(), _Ptr, static_cast<size_t>(_Size));
                _Ptr += _Size;
                _Count -= _Size;
                pbump(static_cast<int>(_Size));
            } else if (_Traits::eq_int_type(_Traits::eof(), overflow(_Traits::to_int_type(*_Ptr)))) {
                break; // single character put failed, quit
            } else { // count character successfully put
                ++_Ptr;
                --_Count;
            }
        }

        return _Start_count - _Count;
    }

    virtual pos_type __CLR_OR_THIS_CALL seekoff(off_type, ios_base::seekdir,
        ios_base::openmode = ios_base::in | ios_base::out) { // change position by offset, according to way and mode
        return streampos(-1);
    }

    virtual pos_type __CLR_OR_THIS_CALL seekpos(pos_type,
        ios_base::openmode = ios_base::in | ios_base::out) { // change to specified position, according to mode
        return streampos(-1);
    }

    virtual basic_streambuf* __CLR_OR_THIS_CALL setbuf(
        _Elem*, streamsize) { // offer buffer to external agent (do nothing)
        return this;
    }

    virtual int __CLR_OR_THIS_CALL sync() { // synchronize with external agent (do nothing)
        return 0;
    }

    virtual void __CLR_OR_THIS_CALL imbue(const locale&) { // set locale to argument (do nothing)
    }

private:
    _Elem* _Gfirst; // beginning of read buffer
    _Elem* _Pfirst; // beginning of write buffer
    _Elem** _IGfirst; // pointer to beginning of read buffer
    _Elem** _IPfirst; // pointer to beginning of write buffer
    _Elem* _Gnext; // current position in read buffer
    _Elem* _Pnext; // current position in write buffer
    _Elem** _IGnext; // pointer to current position in read buffer
    _Elem** _IPnext; // pointer to current position in write buffer

    int _Gcount; // length of read buffer
    int _Pcount; // length of write buffer
    int* _IGcount; // pointer to length of read buffer
    int* _IPcount; // pointer to length of write buffer

protected:
    locale* _Plocale; // pointer to imbued locale object
};

#if defined(_DLL_CPPLIB)

#if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template class _CRTIMP2_PURE_IMPORT basic_streambuf<char, char_traits<char>>;
template class _CRTIMP2_PURE_IMPORT basic_streambuf<wchar_t, char_traits<wchar_t>>;
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)

#ifdef __FORCE_INSTANCE
template class _CRTIMP2_PURE_IMPORT basic_streambuf<unsigned short, char_traits<unsigned short>>;
#endif // __FORCE_INSTANCE
#endif // defined(_DLL_CPPLIB)

// CLASS TEMPLATE istreambuf_iterator
template <class _Elem,
    class _Traits>
class istreambuf_iterator { // wrap stream buffer as input iterator
public:
    using iterator_category = input_iterator_tag;
    using value_type        = _Elem;
    using difference_type   = typename _Traits::off_type;
    using pointer           = const _Elem*;
    using reference         = _Elem;

    using char_type      = _Elem;
    using traits_type    = _Traits;
    using streambuf_type = basic_streambuf<_Elem, _Traits>;
    using istream_type   = basic_istream<_Elem, _Traits>;

    using int_type = typename traits_type::int_type;

    constexpr istreambuf_iterator() noexcept : _Strbuf(nullptr), _Got(true), _Val() {}

    istreambuf_iterator(streambuf_type* _Sb) noexcept
        : _Strbuf(_Sb), _Got(_Sb == nullptr), _Val() { // construct from stream buffer _Sb
    }

    istreambuf_iterator(istream_type& _Istr) noexcept
        : _Strbuf(_Istr.rdbuf()), _Got(_Strbuf == nullptr), _Val() { // construct from stream buffer in istream _Istr
    }

private:
    class _Istreambuf_proxy {
    public:
        _NODISCARD _Elem operator*() const {
            return _Keep;
        }

    private:
        friend istreambuf_iterator;
        _Istreambuf_proxy(streambuf_type* _Strbuf_, _Elem _Keep_) : _Strbuf(_Strbuf_), _Keep(_Keep_) {}

        streambuf_type* _Strbuf;
        _Elem _Keep;
    };

public:
    istreambuf_iterator(const _Istreambuf_proxy& _Px) noexcept
        : _Strbuf(_Px._Strbuf), _Got(_Strbuf == nullptr), _Val() { // construct from proxy
    }

    _NODISCARD _Elem operator*() const { // return designated value
        if (!_Got) {
            _Peek();
        }

#if _ITERATOR_DEBUG_LEVEL == 2
        _STL_VERIFY(_Strbuf != nullptr, "istreambuf_iterator is not dereferencable");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        return _Val;
    }

    istreambuf_iterator& operator++() { // preincrement
#if _ITERATOR_DEBUG_LEVEL == 2
        _STL_VERIFY(_Strbuf != nullptr, "istreambuf_iterator is not incrementable");
#endif // _ITERATOR_DEBUG_LEVEL == 2

        _Inc();
        return *this;
    }

    _Istreambuf_proxy operator++(int) { // postincrement
        if (!_Got) {
            _Peek();
        }

        _Istreambuf_proxy _Tmp{_Strbuf, _Val};
        ++*this;
        return _Tmp;
    }

    _NODISCARD bool equal(const istreambuf_iterator& _Right) const { // test for equality
        if (!_Got) {
            _Peek();
        }

        if (!_Right._Got) {
            _Right._Peek();
        }

        return (_Strbuf == nullptr && _Right._Strbuf == nullptr) || (_Strbuf != nullptr && _Right._Strbuf != nullptr);
    }

private:
    void _Inc() { // skip to next input element
        if (_Strbuf == nullptr || traits_type::eq_int_type(traits_type::eof(), _Strbuf->sbumpc())) {
            _Strbuf = nullptr;
            _Got    = true;
        } else {
            _Got = false;
        }
    }

    _Elem _Peek() const { // peek at next input element
        int_type _Meta;
        if (_Strbuf == nullptr || traits_type::eq_int_type(traits_type::eof(), _Meta = _Strbuf->sgetc())) {
            _Strbuf = nullptr;
        } else {
            _Val = traits_type::to_char_type(_Meta);
        }

        _Got = true;
        return _Val;
    }

    mutable streambuf_type* _Strbuf; // the wrapped stream buffer
    mutable bool _Got; // true if _Val is valid
    mutable _Elem _Val; // next element to deliver
};

template <class _Elem, class _Traits>
_NODISCARD inline bool operator==(const istreambuf_iterator<_Elem, _Traits>& _Left,
    const istreambuf_iterator<_Elem, _Traits>& _Right) { // test for istreambuf_iterator equality
    return _Left.equal(_Right);
}

template <class _Elem, class _Traits>
_NODISCARD inline bool operator!=(const istreambuf_iterator<_Elem, _Traits>& _Left,
    const istreambuf_iterator<_Elem, _Traits>& _Right) { // test for istreambuf_iterator inequality
    return !(_Left == _Right);
}

// CLASS TEMPLATE ostreambuf_iterator
template <class _Elem,
    class _Traits>
class ostreambuf_iterator { // wrap stream buffer as output iterator
public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = void;
    using pointer           = void;
    using reference         = void;

    using char_type      = _Elem;
    using traits_type    = _Traits;
    using streambuf_type = basic_streambuf<_Elem, _Traits>;
    using ostream_type   = basic_ostream<_Elem, _Traits>;

    ostreambuf_iterator(streambuf_type* _Sb) noexcept
        : _Failed(false), _Strbuf(_Sb) { // construct from stream buffer _Sb
    }

    ostreambuf_iterator(ostream_type& _Ostr) noexcept
        : _Failed(false), _Strbuf(_Ostr.rdbuf()) { // construct from stream buffer in _Ostr
    }

    ostreambuf_iterator& operator=(_Elem _Right) { // store element and increment
        if (_Strbuf == nullptr || traits_type::eq_int_type(_Traits::eof(), _Strbuf->sputc(_Right))) {
            _Failed = true;
        }

        return *this;
    }

    _NODISCARD ostreambuf_iterator& operator*() { // pretend to get designated element
        return *this;
    }

    ostreambuf_iterator& operator++() { // pretend to preincrement
        return *this;
    }

    ostreambuf_iterator& operator++(int) { // pretend to postincrement
        return *this;
    }

    _NODISCARD bool failed() const noexcept { // return true if any stores failed
        return _Failed;
    }

private:
    bool _Failed; // true if any stores have failed
    streambuf_type* _Strbuf; // the wrapped stream buffer
};
_STD_END

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // RC_INVOKED
#endif // _STREAMBUF_

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
